import Axios, { type AxiosError, type AxiosInstance, type AxiosRequestConfig, type AxiosResponse,
} from 'axios'
import { showFailToast, showNotify } from 'vant'
import NProgress from './progress'
import { ContentTypeEnum, ResultEnum } from '@/enums/requestEnum'
import 'vant/es/toast/style'
import { SessionStorage } from '@/utils/storage'
import { isNullOrUnDef } from '@/utils/is'
import { globalSetting } from '@/constant'
import router from '@/router'
import { useSystemInfo } from '@/store/system'

const scene = SessionStorage.getItem('scene')
const baseURL = scene === 'marketing' ? globalSetting.mktapi : globalSetting.baseUrl
// 默认 axios 实例请求配置
const configDefault = {
  headers: {
    'Content-Type': ContentTypeEnum.FORM_URLENCODED,
  },
  timeout: 0,
  baseURL,
  data: {},
}

class Http {
  // 当前实例
  private static axiosInstance: AxiosInstance
  // 请求配置
  private static axiosConfigDefault: AxiosRequestConfig

  // 请求拦截
  private httpInterceptorsRequest(): void {
    Http.axiosInstance.interceptors.request.use(
      (config) => {
        NProgress.start()
        const Token = useSystemInfo().getToken()
        if (!isNullOrUnDef(Token))
          config.headers.token = Token

        return config
      },
      (error: AxiosError) => {
        showFailToast(error.message || '网络错误')
        return Promise.reject(error)
      },
    )
  }

  // 响应拦截
  private httpInterceptorsResponse(): void {
    Http.axiosInstance.interceptors.response.use(
      (response: AxiosResponse) => {
        NProgress.done()
        // 与后端协定的返回字段
        const { code, data, result, message } = response.data
        // const { message } = response.data;
        // 判断请求是否成功
        const isSuccess
        = result
        && Reflect.has(response.data, 'code')
        && code === ResultEnum.SUCCESS
        if (isSuccess) {
          return data
        }
        else {
          // 处理请求错误
          // showFailToast(message);
          if (code === ResultEnum.NO_AUTH) {
            SessionStorage.removeItem('token')
            SessionStorage.removeItem('requestTxId')
            showNotify({
              message,
              color: '#DC5858',
              lockScroll: true,
            })
            // const scene = SessionStorage.getItem('scene')
            // const version = SessionStorage.getItem('version')
            // if (scene && version)
            //   router.replace(`/${scene}/${version}/?channelId=${SessionStorage.getItem('channelCode')}`)
            // else
            router.replace('/')
          }
          else {
            showNotify(message || '网络异常')
          }
          return Promise.reject(response.data)
        }
      },
      (error: AxiosError) => {
        NProgress.done()
        // 处理 HTTP 网络错误
        let message = ''
        // HTTP 状态码
        const status = error.response?.status
        switch (status) {
          case 400:
            message = '请求错误'
            break
          case 401:
            message = '未授权，请登录'
            break
          case 403:
            message = '拒绝访问'
            break
          case 404:
            message = `请求地址出错: ${error.response?.config?.url}`
            break
          case 408:
            message = '请求超时'
            break
          case 500:
            message = '服务器内部错误'
            break
          case 501:
            message = '服务未实现'
            break
          case 502:
            message = '网关错误'
            break
          case 503:
            message = '服务不可用'
            break
          case 504:
            message = '网关超时'
            break
          case 505:
            message = 'HTTP版本不受支持'
            break
          default:
            message = '网络连接故障'
        }

        showFailToast(message)
        return Promise.reject(error)
      },
    )
  }

  constructor(config: AxiosRequestConfig) {
    Http.axiosConfigDefault = config
    Http.axiosInstance = Axios.create(config)
    this.httpInterceptorsRequest()
    this.httpInterceptorsResponse()
  }

  // 通用请求函数
  public request<T>(paramConfig: AxiosRequestConfig): Promise<T> {
    const config = { ...Http.axiosConfigDefault, ...paramConfig }
    return new Promise((resolve, reject) => {
      Http.axiosInstance
        .request(config)
        .then((response: any) => {
          resolve(response)
        })
        .catch((error) => {
          reject(error)
        })
    })
  }
}

export const http = new Http(configDefault)
